﻿//
// eCRAM, a monthly activity report web application
// Copyright (C) 2010  Aptea
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;

namespace eCRAM.Tools
{
    public static class WorkingDay
    {
        public static List<String> DayList(DateTime dateTime)
        {
            List<String> ret;
            switch (dateTime.DayOfWeek)
            {
                case DayOfWeek.Monday:
                    ret = new List<string> { "L", "Ma", "Me", "J", "V", "S", "D" };
                    break;
                case DayOfWeek.Tuesday:
                    ret = new List<string> { "Ma", "Me", "J", "V", "S", "D", "L" };
                    break;
                case DayOfWeek.Wednesday:
                    ret = new List<string> { "Me", "J", "V", "S", "D", "L", "Ma" };
                    break;
                case DayOfWeek.Thursday:
                    ret = new List<string> { "J", "V", "S", "D", "L", "Ma", "Me" };
                    break;
                case DayOfWeek.Friday:
                    ret = new List<string> { "V", "S", "D", "L", "Ma", "Me", "J" };
                    break;
                case DayOfWeek.Saturday:
                    ret = new List<string> { "S", "D", "L", "Ma", "Me", "J", "V" };
                    break;
                default:
                    ret = new List<string> { "D", "L", "Ma", "Me", "J", "V", "S" };
                    break;
            }
            return ret;
        }
        
        public static List<bool> MonthWorkingDays(DateTime dateTime)
        {
            List<bool> bolWorkingDay = new List<bool>();
            int monthRef = dateTime.Month;
            dateTime = new DateTime(dateTime.Year, dateTime.Month, 1);
            Array arrDateFerie = Array.CreateInstance(typeof(DateTime), 8);
            // 01 Janvier
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 1, 1), 0);
            // 01 Mai
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 5, 1), 1);
            // 08 Mai
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 5, 8), 2);
            // 14 Juillet
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 7, 14), 3);
            // 15 Aout
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 8, 15), 4);
            // 01 Novembre
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 11, 1), 5);
            // 11 Novembre
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 11, 11), 6);
            // Noël
            arrDateFerie.SetValue(new DateTime(dateTime.Year, 12, 25), 7);

            // Calcul du jour de pâques (algorithme de Oudin (1940))
            //Calcul du nombre d'or - 1
            int intGoldNumber = (int)(dateTime.Year % 19);
            // Année divisé par cent
            int intAnneeDiv100 = (int)(dateTime.Year / 100);
            // intEpacte est = 23 - Epacte (modulo 30)
            int intEpacte =
                (int)
                ((intAnneeDiv100 - intAnneeDiv100 / 4 - (8 * intAnneeDiv100 + 13) / 25 + (19 * intGoldNumber) + 15) % 30);
            //Le nombre de jours à partir du 21 mars pour atteindre la pleine lune Pascale
            int intDaysEquinoxeToMoonFull =
                (int)
                (intEpacte - (intEpacte / 28) * (1 - (intEpacte / 28) * (29 / (intEpacte + 1)) * ((21 - intGoldNumber) / 11)));
            //Jour de la semaine pour la pleine lune Pascale (0=dimanche)
            int intWeekDayMoonFull =
                (int)
                ((dateTime.Year + dateTime.Year / 4 + intDaysEquinoxeToMoonFull + 2 - intAnneeDiv100 +
                  intAnneeDiv100 / 4) % 7);
            // Nombre de jours du 21 mars jusqu'au dimanche de ou
            // avant la pleine lune Pascale (un nombre entre -6 et 28)
            int intDaysEquinoxeBeforeFullMoon = intDaysEquinoxeToMoonFull - intWeekDayMoonFull;
            // mois de pâques
            int intMonthPaques = (int)(3 + (intDaysEquinoxeBeforeFullMoon + 40) / 44);
            // jour de pâques
            int intDayPaques = (int)(intDaysEquinoxeBeforeFullMoon + 28 - 31 * (intMonthPaques / 4));
            // lundi de pâques
            DateTime dtMondayPaques = new DateTime(dateTime.Year, intMonthPaques, intDayPaques + 1);
            // Ascension
            DateTime dtAscension = dtMondayPaques.AddDays(38);
            //Pentecote
            DateTime dtMondayPentecote = dtMondayPaques.AddDays(49);
            
            
            while (dateTime.Month == monthRef)
            {
                // Dimanche ou jour férié
                bool currentDay = !((dateTime.DayOfWeek == DayOfWeek.Sunday) || (dateTime.DayOfWeek == DayOfWeek.Saturday) ||
                                    (Array.BinarySearch(arrDateFerie, dateTime) >= 0));
                if (currentDay)
                {
                    
                    currentDay =
                        !((DateTime.Compare(dtMondayPaques, dateTime) == 0) ||
                          (DateTime.Compare(dtAscension, dateTime) == 0) ||
                          (DateTime.Compare(dtMondayPentecote, dateTime) == 0));
                }
                bolWorkingDay.Add(currentDay);
                try
                {
                    dateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day + 1);
                }
                catch(Exception)
                {
                    return bolWorkingDay;
                }
            }
            return bolWorkingDay;
        }
    }
}
